﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace JCSoft.Collect.Data
{
    public interface IRepositoryFactory
    {
        TRepository Create<TRepository>();
    }

    public class RepositoryFactory : IRepositoryFactory
    {
        private ReaderWriterLockSlim m_rwLock = new ReaderWriterLockSlim();
        private Dictionary<Type, Type> m_repositoryTypeMapping = new Dictionary<Type, Type>();

        #region IRepositoryFactory Members

        public TRepository Create<TRepository>()
        {
            Type interfaceType = typeof(TRepository);
            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException("TRepository must be interface.", "TRepository");
            }

            var repositoryType = this.GetRepositoryType(interfaceType);
            return (TRepository)Activator.CreateInstance(repositoryType);
        }

        private Type GetRepositoryType(Type interfaceType)
        {
            this.m_rwLock.EnterReadLock();
            try
            {
                Type repositoryType;
                if (this.m_repositoryTypeMapping.TryGetValue(interfaceType, out repositoryType))
                {
                    return repositoryType;
                }
            }
            finally
            {
                this.m_rwLock.ExitReadLock();
            }

            this.m_rwLock.EnterWriteLock();
            try
            {
                string typeName = interfaceType.FullName.Replace(".I", ".");
                Type repositoryType = this.GetType().Assembly.GetType(typeName, true);
                this.m_repositoryTypeMapping[interfaceType] = repositoryType;
                return repositoryType;
            }
            finally
            {
                this.m_rwLock.ExitWriteLock();
            }
        }

        #endregion
    }
}
